package com.blackrock.das.web.controllers;

import static com.blackrock.das.enums.Resolution.DAILY;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.joda.time.DateTime;
import org.joda.time.Days;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.blackrock.das.enums.DataType;
import com.blackrock.das.enums.Resolution;
import com.blackrock.das.service.PortfolioService;

/**
 * The Class GraphsController.
 */
@Controller
public class GraphsController {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory.getLogger(GraphsController.class);

    /** The Constant LIMIT_WEEKLY. */
    private static final int LIMIT_WEEKLY = 1200;

    /** The Constant LIMIT_DAILY. */
    private static final int LIMIT_DAILY = 500;

    /** The portfolio service. */
    @Autowired
    private PortfolioService portfolioService;

    /**
     * Register binders.
     *
     * @param binder the binder
     */
    @InitBinder
    public void registerBinders(WebDataBinder binder) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        binder.registerCustomEditor(Date.class, new CustomDateEditor(format, true));
    }

    /**
     * Display no sql graph.
     *
     * @param model the model
     * @return the string
     */
    @RequestMapping("/graph-nosql")
    public String displayNoSqlGraph(Model model) {

        Map<String, Map<String, BigDecimal>> timeSeriesData;
        long start, end;

        List<String> portfoliosIsin = portfolioService.getPorfoliosIsin();
        if (isNotEmpty(portfoliosIsin)) {

            // Set the default isin to be the first returned from the DB.
            String defaultIsin = portfoliosIsin.get(0);

            // Get the static data for all portfolios to populate the drop down
            Map<String, Map<String, Object>> portfolioStaticDataMap = new HashMap<String, Map<String, Object>>();
            for (String isin : portfoliosIsin) {
                Map<String, Object> staticData = portfolioService.getStaticData(isin);
                portfolioStaticDataMap.put(isin, staticData);
            }

            // Get the time series static data for the default isin
            Date startDate = (Date) portfolioStaticDataMap.get(defaultIsin).get("inceptionDate");
            start = System.currentTimeMillis();
            timeSeriesData = portfolioService.getTimeSeriesData(defaultIsin, startDate, new Date(), DAILY);
            end = System.currentTimeMillis();

            model.addAttribute("isin", defaultIsin);
            model.addAttribute("timeSeriesData", timeSeriesData);
            model.addAttribute("portfolioStaticDataMap", portfolioStaticDataMap);
            model.addAttribute("queryExecutionTime", end - start);
        }

        return "graph-nosql";
    }

    /**
     * Update graph data.
     *
     * @param model the model
     * @param isin the isin
     * @param startDate the start date
     * @param endDate the end date
     * @param dataType the data type
     * @return the string
     */
    @RequestMapping("/updateGraphData")
    @ResponseBody
    public Map<String, Map<String, BigDecimal>> updateGraphData(Model model, @RequestParam("isin") String isin,
            @RequestParam("startDate") Date startDate, @RequestParam("endDate") Date endDate, @RequestParam("dataType") Set<String> dataType) {

        Days daysBetween = Days.daysBetween(new DateTime(startDate), new DateTime(endDate));
        int days = daysBetween.getDays();
        Resolution resolution = Resolution.DAILY;

        if (days > LIMIT_WEEKLY) {
            resolution = Resolution.MONTHLY;
        } else if (days > LIMIT_DAILY) {
            resolution = Resolution.WEEKLY;
        }

        Set<DataType> types = new HashSet<DataType>();
        for (String type : dataType) {

            DataType typeForColumnName = DataType.getTypeForColumnName(type);
            if (typeForColumnName != null) {
                types.add(typeForColumnName);

            } else {
                LOGGER.warn(String.format("Column '%s' wasnt recognized", type));
            }
        }

        return portfolioService.getTimeSeriesData(isin, startDate, endDate, resolution, types);
    }

    /**
     * Display das client graph.
     *
     * @param model the model
     * @return the string
     */
    @RequestMapping("/graph-das-client")
    public String displayDasClientGraph(Model model) {
        return "graph-das-client";
    }

}
